home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 22 / Cream of the Crop 22.iso / os2 / blt2_212.zip / src / bd_rix.c < prev    next >
C/C++ Source or Header  |  1996-10-16  |  20KB  |  667 lines

  1.  
  2. /* bd_rix.c -  4-Oct-1996 Cornel Huth
  3.  * This module is called by bd_main.c
  4.  * REINDEX_XB
  5.  */
  6.  
  7. #include "platform.h"
  8.  
  9. // external to this module
  10.  
  11. void PutMsg(CHAR *strg);
  12. void GetMsg(CHAR *strg);
  13.  
  14. extern CHAR *collateTable;
  15.  
  16. #if FOR_WINDOWS == 1
  17.  void DoWinThing(int waitFlag);
  18. #endif
  19.  
  20. // public in this module
  21.  
  22. int bd_rix(void);
  23.  
  24. void __cdecl CallbackRix(CALLBACKPACK *CBP);  // *CBP on stack; caller OR callee may clean stack
  25. void APIENTRY ThreadRix(ACCESSPACK *AP);      // OS-called thread routine
  26.  
  27. LONG rezRix=0;   // thread reindex return code
  28. TID tidRix;      // reindex thread ID  (OS/2=TID, Win32=DWORD)
  29. HANDLE hRix;     // reindex thread's handle (Win32 only)
  30. LONG recs2add;   // records to add en-masse (also used in CallbackRix())
  31.  
  32. // GO
  33.  
  34. int bd_rix(void) {
  35.  
  36.  void BuildFieldListRix(FIELDDESCTYPE fieldList[]);
  37.  
  38. #pragma pack(1)
  39.  
  40.  ACCESSPACK AP;
  41.  DOSFILEPACK DFP;
  42.  CREATEDATAPACK CDP;
  43.  CREATEINDEXPACK CIP;
  44.  HANDLEPACK HP;
  45.  OPENPACK OP;
  46.  QUERYSETPACK QSP;
  47.  STATINDEXPACK SIP;   // for separate thread reindex percentage done
  48.  
  49.  struct EmpRecType {
  50.   CHAR tag;              // record tag, init to SPACE, * means deleted
  51.   CHAR empID[9];         // SSN (not 0T string)
  52.   CHAR empLN[16];        // last name
  53.   CHAR empFN[16];        // first name
  54.   CHAR empHire[8];       // "YYYYMMDD" (not 0T string)
  55.   CHAR empDept[6];       // department assigned
  56.  }; // 56 bytes
  57.  struct EmpRecType EmpRec;
  58.  
  59. #pragma pack()   // no more Bullet-accessed data structures follow
  60.  
  61.  time_t startTime, endTime;
  62.  int display = 0;          // display results or not flag
  63.  int thread = 1;           // dispatch reindex in a thread flag
  64.  int lastNameVar;          // used to construct on-the-fly data record...
  65.  int lastFourVar;          // ...that is unique
  66.  
  67.  LONG rez;                 // return value from Bullet
  68.  
  69.  CHAR nameIX3[] = ".\\$bd_rix.ix3"; // name of index file created
  70.  ULONG indexID=0;                // handle of index file
  71.  CHAR keyExpression[128];        // key expression string buffer (159 max)
  72.  CHAR keyBuffer[68];             // buffer used to store/receive key values
  73.  
  74.  CHAR nameData[] = ".\\$bd_rix.dbf";// name of data file created
  75.  ULONG dataID=0;                 // handle of data file
  76.  FIELDDESCTYPE fieldList[5];     // 5 fields used in data record
  77.  
  78.  LONG i;                 // counter
  79.  CHAR tmpStr[128];       // misc stuff, non-Bullet related
  80.  CHAR putStr[128];
  81.  ULONG tmpU;
  82.  
  83.  SIP.func = 0; // init+ref it for DOSX32 compile
  84.  
  85.  // set field descriptor info for DBF data file created later
  86.  
  87.  memset(fieldList,0,sizeof(fieldList));  // init unused bytes to 0 (required)
  88.  BuildFieldListRix(fieldList);
  89.  
  90.  
  91.  // Use 300K for workspace in reindex module (min is 48K, max is whatever you want)
  92.  // Note: larger is not necessarily faster; it depends on the data order
  93.  #define NEW_XBUFF_SIZE (300*1024)
  94.  
  95.  QSP.func = SET_SYSVARS_XB;
  96.  QSP.item = REINDEX_BUFFER_SIZE;
  97.  QSP.itemValue = NEW_XBUFF_SIZE;
  98.  rez = BULLET(&QSP);
  99.  if (rez) {
  100.     sprintf(putStr,"Failed SET_SYSVARS_XB #%d (reindex buffer size) call.  Err: %d\n",QSP.item,rez);
  101.     PutMsg(putStr);
  102.     goto Abend;
  103.  }
  104.  
  105.  tmpU = QSP.itemValue;              // 0=default, or 144KB total buffer space
  106.  if (tmpU == 0) tmpU = (144*1024);
  107.  sprintf(putStr,"Bullet reindex tmp buffer was %d KB, now %d KB\n", tmpU/1024,
  108.                                                                      NEW_XBUFF_SIZE/1024);
  109.  PutMsg(putStr);
  110.  
  111.  // Delete previous files from any previous run (disregard any error return)
  112.  
  113.  DFP.func = DELETE_FILE_DOS;
  114.  DFP.filenamePtr = nameData;
  115.  rez = BULLET(&DFP);
  116.  DFP.filenamePtr = nameIX3;
  117.  rez = BULLET(&DFP);
  118.  
  119.  
  120.  // Create the data file, a standard DBF (ID=3) as defined in fieldList above.
  121.  
  122.  CDP.func = CREATE_DATA_XB;
  123.  CDP.filenamePtr = nameData;
  124.  CDP.noFields = 5;
  125.  CDP.fieldListPtr = fieldList;
  126.  CDP.fileID = 0x03;
  127.  rez = BULLET(&CDP);
  128.  if (rez) {
  129.     sprintf(putStr,"Failed data file create.  Err: %d\n",rez);
  130.     PutMsg(putStr);
  131.     goto Abend;
  132.  }
  133.  
  134.  
  135.  // Open the data file (required before creating an index file for it)
  136.  
  137.  OP.func = OPEN_DATA_XB;
  138.  OP.filenamePtr = nameData;
  139.  OP.asMode = READWRITE | DENYNONE;
  140.  rez = BULLET(&OP);
  141.  if (rez) {
  142.     sprintf(putStr,"Failed data file open.  Err: %d\n",rez);
  143.     PutMsg(putStr);
  144.     goto Abend;
  145.  }
  146.  dataID = OP.handle;
  147.  
  148.  
  149.  // Create an index file for the data file opened above.
  150.  // This example uses a multi-part key composed of parts of last name and SSN.
  151.  
  152.  strcpy(keyExpression,"SUBSTR(LNAME,1,4)+SUBSTR(SSN,6,4)");
  153.  
  154.  CIP.func = CREATE_INDEX_XB;
  155.  CIP.filenamePtr = nameIX3;
  156.  CIP.keyExpPtr = keyExpression;
  157.  CIP.xbLink = dataID;            // the handle of the data file
  158.  CIP.sortFunction = NLS_SORT | SORT_SET;  // sort by NLS (SORT_SET defined in PLATFORM.H)
  159.  CIP.codePage = CODEPAGE;        // code page to use, or 0 for system default
  160.  CIP.countryCode = CTRYCODE;     // country code...
  161.  CIP.collatePtr = collateTable;  // (see #define INT2165xxNS above)
  162.  CIP.nodeSize = 512;             // 512-byte node size (or 1024, 2048 bytes)
  163.  rez = BULLET(&CIP);
  164.  if (rez) {
  165.     sprintf(putStr,"Failed index file create.  Err: %d\n",rez);
  166.     PutMsg(putStr);
  167.     goto Abend;
  168.  }
  169.  
  170.  
  171.  // Open the index file (what we just created above).
  172.  // As with the index-create, the index-open requires the handle of the data
  173.  // file which this index file indexes.
  174.  
  175.  OP.func = OPEN_INDEX_XB;
  176.  OP.filenamePtr = nameIX3;
  177.  OP.asMode = READWRITE | DENYNONE;
  178.  OP.xbLink = dataID;
  179.  rez = BULLET(&OP);
  180.  if (rez) {
  181.     sprintf(putStr,"Failed index file open.  Err: %d\n",rez);
  182.     PutMsg(putStr);
  183.     goto Abend;
  184.  }
  185.  indexID = OP.handle;
  186.  
  187.  
  188.  PutMsg("Display all data accessed (slower results)? (y/N) ");
  189.  GetMsg(tmpStr);
  190.  if (*tmpStr=='y') display = 1;
  191.  
  192. #if PLATFORM == ON_OS2 || PLATFORM == ON_WIN32 && FOR_WINDOWS == 0
  193.   PutMsg("  Dispatch REINDEX_XB in a separate thread? (Y/n) ");
  194.   GetMsg(tmpStr);
  195.   if (*tmpStr=='n') thread = 0;
  196. #else
  197.   thread = 0;
  198. #endif
  199.  
  200.  PutMsg("  How many records do you want for this test run? ");
  201.  GetMsg(tmpStr);
  202.  recs2add = atol(tmpStr);
  203.  
  204.  if (recs2add < 1) recs2add = 1;         // would you rather end the test?
  205.  if (recs2add > 9999999) recs2add = 1;   // why wait around for 10M?
  206.  
  207.  
  208.  // Add the data records, which are created here, on-the-fly, varying enough
  209.  // to make unique records.
  210.  
  211.  lastFourVar = 1;                        // 0001 start (as used in strncpy() below)
  212.  lastNameVar = 0;                        // 0000 start
  213.  
  214.  EmpRec.tag = ' ';                       // set to not-deleted
  215.  strncpy(EmpRec.empID,"465990001",9);    // only changing last 4 in test
  216.  strcpy(EmpRec.empLN,"0000LastNameNum"); // only changing first 4 in test
  217.  strcpy(EmpRec.empFN,"YourFirstName");   // everyone has this first name!
  218.  strncpy(EmpRec.empHire,"19950527",8);   // YYYYMMDD DBF form, no \0 on date
  219.  strcpy(EmpRec.empDept,"MIS");           // everyone works for MIS!
  220.  
  221.  sprintf(putStr,"    Adding %d records...  ",recs2add);
  222.  PutMsg(putStr);
  223.  
  224.  time(&startTime);
  225.  
  226.  AP.func = ADD_RECORD_XB;
  227.  AP.handle = dataID;
  228.  AP.recPtr = &EmpRec;
  229.  for (i = 1; i <= recs2add; i++) {
  230.  
  231.     sprintf(tmpStr,"%4.4i",lastFourVar++);
  232.     strncpy(EmpRec.empID+5,tmpStr,4);            // update last 4 of empID
  233.     rez = BULLET(&AP);                           // AP. already setup
  234.     if (rez) {
  235.        sprintf(putStr,"Failed while adding record %d.  Err: %d\n",i,rez);
  236.        PutMsg(putStr);
  237.        goto Abend;
  238.     }
  239.     if (lastFourVar > 9999) {                    // changes every 10,000 adds
  240.        lastFourVar = 0;                          // where name takes carry ...
  241.        sprintf(tmpStr,"%4.4i",++lastNameVar);
  242.        strncpy(EmpRec.empLN,tmpStr,4);           // update first 4 of empLN
  243.     }
  244.  
  245. #if FOR_WINDOWS == 1                   // deal with message queue every now and then
  246.     if (i % Q_ADD == 0) DoWinThing(0); // 0=no waiting around
  247. #endif
  248.  
  249.  }
  250.  time(&endTime);
  251.  sprintf(putStr,"took %u secs.\n",(endTime - startTime));
  252.  PutMsg(putStr);
  253.  
  254.  
  255.  // Reindex
  256.  
  257.  sprintf(putStr,"Reindexing %d records...  \r",recs2add);
  258.  PutMsg(putStr);
  259.  
  260.  time(&startTime);
  261.  
  262.  AP.func = REINDEX_XB;           // this is all there is to reindexing even...
  263.  AP.handle = indexID;            // ...million-record databases
  264.  AP.keyPtr = keyBuffer;          // if dup key error...(see manual for details)
  265.  AP.nextPtr = NULL;              // just this one index file
  266.  
  267.  if (thread) {
  268.  
  269. #if PLATFORM == ON_DOSX32
  270.  
  271.     PutMsg(" Threads are not supported on this OS\n");
  272.     goto Abend;
  273.  
  274. #elif PLATFORM == ON_OS2
  275.  
  276.     rez = DosCreateThread(&tidRix,
  277.                           (PFNTHREAD) &ThreadRix,
  278.                           (ULONG) &AP,
  279.                           CREATE_READY | STACK_SPARSE,
  280.                           32768);  // min is 8K stack
  281.     if (rez) {
  282.        sprintf(putStr,"Could not start reindex thread.  Err: %d\n",rez);
  283.        PutMsg(putStr);
  284.        goto Abend;
  285.     }
  286.  
  287.     DosSleep(32);  // wait a bit to let reindex code set progress to non-zero
  288.  
  289.     // could also use a callback routine to put out a reindex % number
  290.  
  291.     SIP.func = STAT_INDEX_XB;
  292.     SIP.handle = indexID;
  293.     rez = BULLET(&SIP);
  294.     while (rez==0) {
  295.        DosSleep(100);
  296.        sprintf(putStr,"Reindexing %d records... %3.3u%%\r",recs2add,SIP.progress);
  297.        PutMsg(putStr);
  298.        rez = BULLET(&SIP);
  299.        if (SIP.progress==0) {
  300.           sprintf(putStr,"Reindexing %d records...  ",recs2add);
  301.           PutMsg(putStr);
  302.           break;
  303.        }
  304.     }
  305.     if (rez) {
  306.        sprintf(putStr,"Failed progress check.  Err: %d\n",rez);
  307.        PutMsg(putStr);
  308.     } // continue
  309.  
  310.     // Can actually get here _before_ the reindex thread fully exits, but
  311.     // won't get here until SIP.progress is back to 0.
  312.  
  313.     time(&endTime);
  314.  
  315.     // It's likely that the thread has exited completely by now, but if
  316.     // it was blocked after setting SIP.progress to 0 (hung up in the cache,
  317.     // etc.), then it's possible to get here well before Bullet has exited.
  318.     // Since calling Bullet while Bullet is busy (for most routines) results
  319.     // in a rc=640 being returned (mutex timeout), just call this to wait
  320.     // for the thread to exit completely.  Note that this has only been seen
  321.     // under Win95 (done, but blocked), but this little routine won't hurt.
  322.     // Ignore any error, which there will be if the thread has indeed exited.
  323.     // Another option is to use a non-0 mutex-timeout value, via SET_SYSVARS_XB.
  324.  
  325.     rez = DosWaitThread(&tidRix,DCWW_WAIT);
  326.     // ignore error (such as "invalid thread ID")
  327.  
  328.     DosSleep(1); // allow the reindex thread to exit BULLET() (and set rez)
  329.  
  330.     rez = rezRix;           // get return code set by ThreadRix()
  331.     if (rez) {              // rez is already AP.stat
  332.        sprintf(putStr,"Failed reindex.  Err: %d\n",rez);
  333.        PutMsg(putStr);
  334.        goto Abend;
  335.     }
  336.     sprintf(putStr,"took %u secs.\n",(endTime - startTime));
  337.     PutMsg(putStr);
  338.  
  339. #elif PLATFORM == ON_WIN32
  340.  
  341.     hRix = CreateThread(NULL,
  342.                         32768,               // 8KB min.
  343.                         (LPTHREAD_START_ROUTINE) &ThreadRix,
  344.                         (PACCESSPACK) &AP,
  345.                         0,                   // immediate start
  346.                         &tidRix);
  347.  
  348.  
  349.     if (hRix==0) {
  350.        rez = GetLastError();
  351.        sprintf(putStr,"Could not start reindex thread.  Err: %d\n",rez);
  352.        PutMsg(putStr);
  353.        goto Abend;
  354.     }
  355.  
  356.     Sleep(32);   // wait a bit to let reindex code set progress to non-zero
  357.  
  358.     SIP.func = STAT_INDEX_XB;
  359.     SIP.handle = indexID;
  360.     rez = BULLET(&SIP);
  361.     while (rez==0) {
  362.        Sleep(100);
  363.        sprintf(putStr,"Reindexing %d records... %3.3u%%\r",recs2add,SIP.progress);
  364.        PutMsg(putStr);
  365.        rez = BULLET(&SIP);
  366.        if (SIP.progress==0) {
  367.           sprintf(putStr,"Reindexing %d records...  ",recs2add);
  368.           PutMsg(putStr);
  369.           break;
  370.        }
  371.     }
  372.     if (rez) {
  373.        sprintf(putStr,"Failed progress check.  Err: %d\n",rez);
  374.        PutMsg(putStr);
  375.     } // continue
  376.  
  377.  
  378.     // Can actually get here _before_ the reindex thread fully exits, but
  379.     // won't get here until SIP.progress is back to 0.
  380.  
  381.     time(&endTime);
  382.  
  383.     // It's likely that the thread has exited completely by now, but if
  384.     // it was blocked after setting SIP.progress to 0 (hung up in the cache,
  385.     // etc.), then it's possible to get here well before Bullet has exited.
  386.     // Since calling Bullet while Bullet is busy (for most routines) results
  387.     // in a rc=640 being returned (mutex timeout), just call this to wait
  388.     // for the thread to exit completely.  Note that this has only been seen
  389.     // under Win95 (done, but blocked), but this little routine won't hurt.
  390.     // Ignore any error, which there will be if the thread has indeed exited.
  391.     // Another option is to use a non-0 mutex-timeout value, via SET_SYSVARS_XB.
  392.     // Error code 640 is documented in BULLET_2.H.
  393.  
  394.     rez = WaitForSingleObject(hRix,10*1000); // 10 secs plenty of flush time
  395.     // ignore error
  396.  
  397.     Sleep(32);   // allow the reindex thread to exit BULLET() (and set rez)
  398.                  // why 32ms?  Only because OS/2 min std resolution is 32ms
  399.  
  400.     rez = rezRix;       // get return code set by ThreadRix()
  401.     if (rez) {              // rez is already AP.stat
  402.        sprintf(putStr,"Failed reindex.  Err: %d\n",rez);
  403.        PutMsg(putStr);
  404.        goto Abend;
  405.     }
  406.     sprintf(putStr,"took %u secs.\n",(endTime - startTime));
  407.     PutMsg(putStr);
  408.  
  409. #endif
  410.  
  411.  }
  412.  else {
  413.  
  414.     // no separate thread, so use callback (especially useful for DOSX32 and Win32s)
  415.  
  416.     QSP.func = SET_SYSVARS_XB;
  417.     QSP.item = CALLBACK_PTR;
  418.     QSP.itemValue = (ULONG) &CallbackRix;
  419.     rez = BULLET(&QSP);
  420.     if (rez) {
  421.        sprintf(putStr,"Failed SET_SYSVARS_XB #%d (callback address) call.  Err: %d\n",QSP.item,rez);
  422.        PutMsg(putStr);
  423.        goto Abend;
  424.     }
  425.  
  426.     // now make actual REINDEX_XB call, set up above
  427.  
  428.     rez = BULLET(&AP);       // rez=0 if okay, or =1 if pack failed with ecode in AP.stat
  429.     if (rez) {
  430.        rez = AP.stat;
  431.        sprintf(putStr,"Failed reindex.  Err: %d\n",rez);
  432.        PutMsg(putStr);
  433.        goto Abend;
  434.     }
  435.     time(&endTime);
  436.     sprintf(putStr,"Reindexing %d records...  took %u secs.\n",recs2add,(endTime - startTime));
  437.     PutMsg(putStr);
  438.  
  439.     // turn off callback
  440.  
  441.     QSP.func = SET_SYSVARS_XB;
  442.     QSP.item = CALLBACK_PTR;
  443.     QSP.itemValue = 0;
  444.     rez = BULLET(&QSP);
  445.     if (rez) {
  446.        sprintf(putStr,"Failed SET_SYSVARS_XB #%d (callback clear) call.  Err: %d\n",QSP.item,rez);
  447.        PutMsg(putStr);
  448.        goto Abend;
  449.     }
  450.  
  451.  }
  452.  
  453.  
  454.  // Get key data
  455.  
  456.  memset(keyBuffer,0,sizeof(keyBuffer));
  457.  sprintf(putStr," Accessing %d keys...     ",recs2add);
  458.  PutMsg(putStr);
  459.  if (display) PutMsg("\n");
  460.  time(&startTime);
  461.  AP.func = FIRST_KEY_XB;
  462.  AP.handle = indexID;
  463.  AP.keyPtr = keyBuffer;
  464.  rez = BULLET(&AP);
  465.  i=0;
  466.  while (rez==0) {
  467.     if (display) {
  468.        sprintf(putStr,"%s  %9.9lu\r", keyBuffer, AP.recNo);
  469.        PutMsg(putStr);
  470.     }
  471.     i++;
  472.     AP.func = NEXT_KEY_XB;
  473.     rez = BULLET(&AP);
  474.  
  475. #if FOR_WINDOWS == 1                   // deal with message queue every now and then
  476.     if (i % Q_KEY == 0) DoWinThing(0); // 0=no waiting around
  477. #endif
  478.  
  479.  }
  480.  time(&endTime);
  481.  if (display) PutMsg("\n...");
  482.  
  483.  // expected rez is EXB_END_OF_FILE
  484.  
  485.  if (rez == EXB_END_OF_FILE) rez=0;
  486.  if (rez) {
  487.     sprintf(putStr,"Failed KEY access.  Err: %d\n",rez);
  488.     PutMsg(putStr);
  489.     goto Abend;
  490.  }
  491.  sprintf(putStr,"took %u secs. for %d keys\n",(endTime - startTime),i);
  492.  PutMsg(putStr);
  493.  
  494.  
  495.  // Get key and record data
  496.  
  497.  sprintf(putStr," Accessing %d keys+recs...",recs2add);
  498.  PutMsg(putStr);
  499.  if (display) PutMsg("\n");
  500.  time(&startTime);
  501.  
  502.  AP.func = GET_FIRST_XB;
  503.  AP.handle = indexID;
  504.  AP.keyPtr = keyBuffer;
  505.  AP.recPtr = &EmpRec;
  506.  rez = BULLET(&AP);
  507.  i=0;
  508.  while (rez==0) {
  509.     if (display) {
  510.        sprintf(putStr,"%s  %9.9lu   %s\r", keyBuffer, AP.recNo, &EmpRec); // partial show
  511.        PutMsg(putStr);
  512.     }
  513.     i++;
  514.     AP.func = GET_NEXT_XB;
  515.     rez = BULLET(&AP);
  516.  
  517. #if FOR_WINDOWS == 1                   // deal with message queue every now and then
  518.     if (i % Q_GET == 0) DoWinThing(0); // 0=no waiting around
  519. #endif
  520.  
  521.  }
  522.  time(&endTime);
  523.  if (display) PutMsg("\n...");
  524.  
  525.  // expected rez is EXB_END_OF_FILE
  526.  
  527.  if (rez == EXB_END_OF_FILE) rez=0;
  528.  if (rez) {
  529.     sprintf(putStr,"Failed GET access.  Err: %d\n",rez);
  530.     PutMsg(putStr);
  531.     goto Abend;
  532.  }
  533.  sprintf(putStr,"took %u secs. for %d keys & records\n",(endTime - startTime),i);
  534.  PutMsg(putStr);
  535.  
  536.  
  537.  // Fatal errors above come straight to here
  538. Abend:
  539.  
  540.  // Close files
  541.  
  542.  if (indexID) {
  543.     HP.func = CLOSE_INDEX_XB;
  544.     HP.handle = indexID;
  545.     rez = BULLET(&HP);
  546.     if (rez) {
  547.        sprintf(putStr,"Failed index file close.  Err: %d\n",rez);
  548.        PutMsg(putStr);
  549.     }
  550.  }
  551.  
  552.  // Unlikely the above could fail, considering how far it has gotten so far!
  553.  // But logic says that we want to continue closing other open files...
  554.  
  555.  if (dataID) {
  556.     HP.func = CLOSE_DATA_XB;
  557.     HP.handle = dataID;
  558.     rez = BULLET(&HP);
  559.     if (rez) {
  560.        sprintf(putStr,"Failed data file close.  Err: %d\n",rez);
  561.        PutMsg(putStr);
  562.     }
  563.  }
  564.  return rez;  // module exit
  565. }
  566.  
  567. ////////////////////
  568. // Support Routines
  569. ////////////////////
  570.  
  571. #if PLATFORM == ON_OS2 || PLATFORM == ON_WIN32
  572.  
  573. // -------------------------
  574. // Reindex thread, thread #2
  575.  
  576. void APIENTRY ThreadRix(ACCESSPACK *AP) {
  577.  
  578.  rezRix = BULLET(AP);
  579.  
  580.  // Reindex is a xaction-list routine and so must check AP.stat for any
  581.  // error code -- rez as returned from the Bullet call is the list item
  582.  // that failed.  Since this example has but the single item, rez=1 on
  583.  // failure, with the error code in AP.stat.
  584.  
  585.  if (rezRix) rezRix = AP->stat;
  586. }
  587. #endif
  588.  
  589.  
  590. //------------------------------------
  591. // Init field list items for data file
  592.  
  593. void BuildFieldListRix(FIELDDESCTYPE fieldList[]) {
  594.  
  595.  strcpy(fieldList[0].fieldName, "SSN");  // field names must be upper-case
  596.  fieldList[0].fieldType = 'C';           // field types must be upper-case
  597.  fieldList[0].fieldLen = 9;
  598.  fieldList[0].fieldDC = 0;
  599.  
  600.  strcpy(fieldList[1].fieldName, "LNAME");
  601.  fieldList[1].fieldType = 'C';
  602.  fieldList[1].fieldLen = 16;
  603.  fieldList[1].fieldDC = 0;
  604.  
  605.  strcpy(fieldList[2].fieldName, "FNAME");
  606.  fieldList[2].fieldType = 'C';
  607.  fieldList[2].fieldLen = 16;
  608.  fieldList[2].fieldDC = 0;
  609.  
  610.  strcpy(fieldList[3].fieldName, "HIRED");
  611.  fieldList[3].fieldType = 'D';
  612.  fieldList[3].fieldLen = 8;      // date field type must be 8.0
  613.  fieldList[3].fieldDC = 0;
  614.  
  615.  strcpy(fieldList[4].fieldName, "DEPT");
  616.  fieldList[4].fieldType = 'C';
  617.  fieldList[4].fieldLen = 6;
  618.  fieldList[4].fieldDC = 0;
  619.  return;
  620. }
  621.  
  622.  
  623. // --------------------------------
  624. // Callback for reindex (no thread)
  625. // This must get parm from stack
  626. // Stack clean up may be caller OR callee
  627. // CBP->callMode == 0 (0=reindex; 1=pack records)
  628. // CBP->data1 is 1 to 99 when working (it starts
  629. // at 1), and is 0 when finished (same as SxP.progress)
  630.  
  631. void __cdecl CallbackRix(CALLBACKPACK *CBP) {
  632.  
  633.  static ULONG pct=0;
  634.  CHAR putStr[128];
  635.  
  636.  if (CBP->data1 > pct) {   // this logic prevents final 0% (all done) from showing
  637.     // W10a fails to carry-forward %% in sprintf so percent sign doesn't display
  638.     pct = CBP->data1;
  639.     sprintf(putStr,"Reindexing %d records... %3.3u%%\r",recs2add,pct);
  640.     PutMsg(putStr);
  641.  }
  642.  
  643.  // when reindex is complete data1 is always set to 0
  644.  // take the opportunity to re-init the static pct var
  645.  // else it'll stay at its last value
  646.  
  647.  if (CBP->data1 == 0) pct=0;
  648.  
  649.  return;
  650.  
  651.  // could also get % this way, but why if already in CBP->data1
  652.  
  653. #if 0
  654.  STATINDEXPACK SIP;
  655.  
  656.  SIP.func = STAT_INDEX_XB;
  657.  SIP.handle = indexID;
  658.  rez = BULLET(&SIP);
  659.  if (SIP.progress != 0) {
  660.     sprintf(putStr,"Reindexing %d records... %3.3u%%\r",recs2add,SIP.progress);
  661.     PutMsg(putStr);
  662.  }
  663.  return;
  664. #endif
  665.  
  666. }
  667.